package com.stone.redis.lock.service.impl;

import com.stone.redis.lock.domain.bo.LockInfo;
import com.stone.redis.lock.service.LockService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

/**
 * 公平锁实现
 *
 * @author Mr_wenpan@163.com 2021/7/24 6:42 下午
 */
@Slf4j
public class FairLockServiceImpl implements LockService {

    @Autowired
    @Qualifier("lockRedissonClient")
    private RedissonClient redissonClient;

    private final ThreadLocal<LockInfo> lockInfoThreadLocal = new ThreadLocal<>();

    @Override
    public void setLockInfo(LockInfo lockInfo) {
        lockInfoThreadLocal.set(lockInfo);
    }

    @Override
    public LockInfo getLockInfo() {
        return lockInfoThreadLocal.get();
    }

    @Override
    public void clearLockInfo() {
        lockInfoThreadLocal.remove();
    }

    @Override
    public boolean lock() {
        LockInfo lockInfo = lockInfoThreadLocal.get();
        RLock rLock = redissonClient.getFairLock(lockInfo.getName());
        try {
            // 获取锁对象，通过RedissonLock来获取锁（RedissonLock实现了RLock接口）
            return rLock.tryLock(lockInfo.getWaitTime(), lockInfo.getLeaseTime(), lockInfo.getTimeUnit());
        } catch (Exception e) {
            log.info("获取公平锁时线程被意外中断，锁名称：{}，异常信息：{}", lockInfo.getName(), e);
            return false;
        }
    }

    @Override
    public void releaseLock() {
        LockInfo lockInfo = lockInfoThreadLocal.get();
        RLock rLock = redissonClient.getFairLock(lockInfo.getName());
        // 如果该锁是被自己持有的
        if (rLock.isHeldByCurrentThread()) {
            rLock.unlockAsync();
        }
        lockInfoThreadLocal.remove();
    }

}